package cn.edu.xmu.oomall.share.service;

import cn.edu.xmu.oomall.core.util.ReturnNo;
import cn.edu.xmu.oomall.core.util.ReturnObject;
import cn.edu.xmu.oomall.share.dao.ShareDao;
import cn.edu.xmu.oomall.share.microservice.CustomerService;
import cn.edu.xmu.oomall.share.microservice.GoodService;
import cn.edu.xmu.oomall.share.microservice.OnSaleService;
import cn.edu.xmu.oomall.share.microservice.ShareActivityService;
import cn.edu.xmu.oomall.share.microservice.vo.CustomerVo;
import cn.edu.xmu.oomall.share.microservice.vo.OnSaleVo;
import cn.edu.xmu.oomall.share.microservice.vo.ProductVo;
import cn.edu.xmu.oomall.share.microservice.vo.SimpleShareActivityVo;
import cn.edu.xmu.oomall.share.model.bo.Share;
import cn.edu.xmu.oomall.share.model.po.SharePo;
import cn.edu.xmu.oomall.share.model.po.SuccessfulSharePo;
import cn.edu.xmu.oomall.share.model.vo.*;
import cn.edu.xmu.privilegegateway.annotation.util.InternalReturnObject;
import com.github.pagehelper.PageInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static cn.edu.xmu.oomall.core.util.Common.getPageRetVo;
import static cn.edu.xmu.privilegegateway.annotation.util.Common.cloneVo;

@Service
public class ShareService {
    private Logger logger = LoggerFactory.getLogger(ShareService.class);
    @Autowired
    private ShareDao shareDao;

    @Autowired
    private OnSaleService onSaleService;

    @Autowired
    private GoodService goodService;

    @Autowired
    private ShareActivityService shareActivityService;

    @Autowired
    private CustomerService customerService;

    @Transactional(rollbackFor = Exception.class)
    public ReturnObject generateShareResult(Long userId, String userName, Long onsaleId) {
        InternalReturnObject internalReturnObject = onSaleService.getOnsaleById(onsaleId);
        if (internalReturnObject.getData() == null) {
            return new ReturnObject(internalReturnObject);
        }
        OnSaleVo onsale = (OnSaleVo) internalReturnObject.getData();
        Long productId = onsale.getProduct().getId();
        Long shareActId = onsale.getShareActId();
        if (shareActId == null) {
            return new ReturnObject(ReturnNo.SHARE_UNSHARABLE);
        }

        InternalReturnObject<ProductVo> productDetails = goodService.getProductDetails(productId);
        ProductVo product = productDetails.getData();
        if (product.getShareable() == false) {
            return new ReturnObject(ReturnNo.SHARE_UNSHARABLE);
        }
        Share share;
        // 查数据库有没有该买家id和商品id的分享链接
        ReturnObject shareRetObj = shareDao.getSharesByUserAndProduct(userId, productId);
        if (shareRetObj.getData() != null) {
            share = (Share) shareRetObj.getData();
        }
        else {
            ReturnObject returnObject = shareDao.insertShare(userId, userName, shareActId, productId, onsaleId);
            share = (Share) returnObject.getData();
            if (returnObject.getData() == null) {
                return returnObject;
            }
        }

        ShareRetVo shareRetVo = cloneVo(share, ShareRetVo.class);
        shareRetVo.setSharer(new SimpleCustomerRetVo(userId, userName));
        shareRetVo.setProduct(onsale.getProduct());
        return new ReturnObject(shareRetVo);
    }

    private ReturnObject assembleSharePageVo(ReturnObject returnObject, String userName) {
        PageInfo pageInfo = (PageInfo) returnObject.getData();
        List<SharePo> sharePoList = (List<SharePo>) pageInfo.getList();

        ReturnObject pageRetVoRetObj = getPageRetVo(returnObject, ShareRetVo.class);
        List<ShareRetVo> shareRetVoList = (List<ShareRetVo>) ((Map) pageRetVoRetObj.getData()).get("list");

        boolean hasUserName = (userName != null);

        // 组装product 和 sharer 和 Id
        for (int i = 0; i < sharePoList.size(); i++) {
            Long onsaleId = sharePoList.get(i).getOnsaleId();
            InternalReturnObject internalReturnObject = onSaleService.getOnsaleById(onsaleId);
            OnSaleVo onSale = (OnSaleVo) internalReturnObject.getData();
            SimpleProductRetVo product;
            if (onSale == null) {
                product = null;
            }
            else {
                product = onSale.getProduct();
            }
            shareRetVoList.get(i).setProduct(product);

            Long userId = sharePoList.get(i).getSharerId();
            if (!hasUserName) {
                InternalReturnObject<CustomerVo> interRet = customerService.getUserById(0L, userId);
                //Todo 未确定是直接返回错误还是设为null
                if (interRet.getData() == null) {
                    userName = null;
                }
                else {
                    userName = interRet.getData().getUserName();
                }
            }
            shareRetVoList.get(i).setSharer(new SimpleCustomerRetVo(userId, userName));
        }
        return pageRetVoRetObj;
    }

    private ReturnObject assembleSucSharePageVo(ReturnObject returnObject) {
        PageInfo pageInfo = (PageInfo) returnObject.getData();
        List<SuccessfulSharePo> sharePoList = (List<SuccessfulSharePo>) pageInfo.getList();

        ReturnObject pageRetVoRetObj = getPageRetVo(returnObject, SuccessfulShareRetVo.class);
        List<SuccessfulShareRetVo> sucShareRetVoList = (List<SuccessfulShareRetVo>) ((Map) pageRetVoRetObj.getData()).get("list");

        // 组装product
        for (int i = 0; i < sharePoList.size(); i++) {
            Long onsaleId = sharePoList.get(i).getOnsaleId();
            InternalReturnObject internalReturnObject = onSaleService.getOnsaleById(onsaleId);
            OnSaleVo onSale = (OnSaleVo) internalReturnObject.getData();
            SimpleProductRetVo product;
            if (onSale == null) {
                product = null;
            }
            else {
                product = onSale.getProduct();
            }
            sucShareRetVoList.get(i).setProduct(product);
        }
        return pageRetVoRetObj;
    }


    @Transactional(readOnly = true, rollbackFor = Exception.class)
    public ReturnObject getShares(Long userId, String userName, Long productId, LocalDateTime beginDate, LocalDateTime endDate, Integer page, Integer pageSize) {
        ReturnObject returnObject = shareDao.getShares(userId, productId, beginDate, endDate, page, pageSize);
        if (returnObject.getData() == null) {
            return returnObject;
        }

        return assembleSharePageVo(returnObject, userName);
    }

    @Transactional(rollbackFor = Exception.class)
    public Object getProductInShareMode(Long userId, Long shareId, Long productId) {
        ReturnObject shareByIdRetObj = shareDao.getShareById(shareId);
        if (shareByIdRetObj.getData() == null) {
            return shareByIdRetObj;
        }
        Share share = (Share) shareByIdRetObj.getData();
        if (!productId.equals(share.getProductId())) {
            //Todo 错误码未确定
            return new ReturnObject(ReturnNo.RESOURCE_ID_NOTEXIST);
        }
        Long onsaleId = share.getOnsaleId();
        Long sharerId = share.getSharerId();
        ReturnObject insertSucShareRetObj = shareDao.insertSuccessfulShare(shareId, sharerId, productId, onsaleId, userId);
        if (insertSucShareRetObj.getCode() != ReturnNo.OK) {
            return insertSucShareRetObj;
        }
        InternalReturnObject<ProductVo> productDetails = goodService.getProductDetails(productId);
        return new ReturnObject<>(productDetails);
    }

    private List<Long> getShareActIdList(Long shopId, Long productId) {
        InternalReturnObject<List<SimpleShareActivityVo>> inRet = shareActivityService.getShareByShopId(shopId, productId);
        if (inRet.getData() == null) {
            return null;
        }
        List<SimpleShareActivityVo> shareActivityRetVoList = inRet.getData();
        List<Long> shareActIdList = shareActivityRetVoList.stream().map(SimpleShareActivityVo::getId).collect(Collectors.toList());
        return shareActIdList;
    }

    @Transactional(readOnly = true, rollbackFor = Exception.class)
    public ReturnObject getSharesOfGoods(Long shopId, Long productId, Integer page, Integer pageSize) {
        List<Long> shareActIdList = getShareActIdList(shopId, productId);
        if (shareActIdList == null) {
            return new ReturnObject(ReturnNo.INTERNAL_SERVER_ERR);
        }

        ReturnObject returnObject = shareDao.getShares(productId, shareActIdList, page, pageSize);
        if (returnObject.getData() == null) {
            return returnObject;
        }

        return assembleSharePageVo(returnObject, null);
    }

    @Transactional(readOnly = true, rollbackFor = Exception.class)
    public ReturnObject getBeShared(Long userId, Long productId, LocalDateTime beginDate, LocalDateTime endDate, Integer page, Integer pageSize) {
        ReturnObject returnObject = shareDao.getSuccessfulShares(userId, productId, beginDate, endDate, page, pageSize);
        if (returnObject.getData() == null) {
            return returnObject;
        }
        return assembleSucSharePageVo(returnObject);
    }

    @Transactional(readOnly = true, rollbackFor = Exception.class)
    public ReturnObject getAllBeShared(Long shopId, Long productId, LocalDateTime beginDate, LocalDateTime endDate, Integer page, Integer pageSize) {
        if (productId != null){
            InternalReturnObject<ProductVo> productDetailsRet = goodService.getProductDetails(productId);
            if (productDetailsRet.getData() == null) {
                return new ReturnObject(ReturnNo.RESOURCE_ID_NOTEXIST);
            }
            ProductVo product = productDetailsRet.getData();
            if (!product.getShop().getId().equals(shopId)) {
                return new ReturnObject(ReturnNo.RESOURCE_ID_OUTSCOPE);
            }
        }
        List<Long> shareActIdList = getShareActIdList(shopId, productId);

        ReturnObject returnObject = shareDao.getSuccessfulShares(shareActIdList, productId, beginDate, endDate, page, pageSize);
        if (returnObject.getData() == null) {
            return returnObject;
        }
        return assembleSucSharePageVo(returnObject);
    }

    public boolean updateBeSharedState(Long id, Byte state) {
        return shareDao.updateBeSharedState(id,state);
    }

    public ReturnObject getBesharedList(Long productId, Long onsaleId, Long customerId) {
        return shareDao.getBesharedList(productId,onsaleId,customerId);
    }

    public void addSharesQuantity(Long id, Long quantity) {
        shareDao.addSharesQuantity(id,quantity);
    }

    public ReturnObject getSharesQuantity(Long id) {
        return shareDao.getSharesQuantity(id);
    }
}